/*
 * This is my client program which takes in four arguments.
 * 	-argv[1] is the server ip address
 * 	-argv[2] is the port of the server
 * 	-argv[3] is the password.
 *	-argv[4] is the command to be executed on the server, this is optional
 *
 * This uses TCP/IP.
 *
 * This was adapted from Claypool's talk-tcp.c code.
 * 
 * By: Jonathan Marokhovsky
 * Version: November 17, 2011
 */
 
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <netdb.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/time.h>

#ifndef INADDR_NONE
#define INADDR_NONE 0xffffffff /* should be in <netinet/in.h> */
#endif

#define MAX_COMMAND	80
#define MAX_BUFFER	80
#define MAX_READ	10000
#define ACCEPTED	"ok"

void exitSocket(int sock, int exitNum);

int debug;

int main(int argc, char *argv[])
{
	char servOut[MAX_READ];
	unsigned long int inAddr;
	int sock, hostPort, bytes, i;
	struct sockaddr_in addr;
	char *hostAddr;
	char *cmd;
	char *pw;
	char theCommand[MAX_COMMAND + 1];
	struct hostent *hp;
	struct timeval tp;
	double dt1, dt2, dt3, dt4; // to measure the change in time
	
	/* initialize anything which needs initializing */
	cmd = theCommand;
	debug = 1;
	
	if (argc < 4) // it is possible to not send a command aka a 'blank' command
	{
		fprintf(stderr, "%s - client to try TCP connection to server", argv[0]);
		fprintf(stderr, "usage: %s <host> <port> <pw> <cmd>\n", argv[0]);
		fprintf(stderr, "\t<host>\t- Internet name of server host\n");
		fprintf(stderr, "\t<port>\t- port\n");
		fprintf(stderr, "\t<pw>\t- password\n");
		fprintf(stderr, "\t<cmd>\t- command to be executed\n");
		exit(1);
	}
	
	hostAddr = argv[1];
	hostPort = atoi(argv[2]);
	pw = argv[3];
		
	/* whatever's left is part of the command */
	for (i = 4; i < argc; i++)
	{
		strncat(cmd, argv[i], MAX_COMMAND);
		if (i < argc - 1)
			strncat(cmd, " ", MAX_COMMAND);
	}
	if (debug) printf("\nThe command which will be used is '%s'\n\n", cmd);
	
	printf("Client created.\n\n");
	printf("Trying to connect to server %s at port %d...\n", hostAddr, hostPort);
	
	/*
	 * Try to convert the host name as a dotted-decimal number.
	 * If that fails, use gethostbyname().
	 */
	bzero((void *) &addr, sizeof(addr));
	printf("Looking up %s...\n", hostAddr);
	if ((hp = gethostbyname(hostAddr)) == NULL)
	{
		perror("host name error");
		exit(2);
	}
	bcopy(hp->h_addr, (char *) &addr.sin_addr, hp->h_length);
	
	printf("Found it. Setting port communcation to %d...\n", hostPort);
	addr.sin_family = AF_INET;
	addr.sin_port = htons(hostPort);
	
	/* open a TCP socket */
	puts("Done. Opening socket...");
	
	gettimeofday(&tp, NULL);
	dt1 = tp.tv_sec+(tp.tv_usec/1000000.0); // start the timer
	if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
	{
		perror("opening socket");
		exit(3);
	}
	
	/* socket open, connect to the server */
	puts("Open. Trying connection to sever...");
	if (connect(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
	{
		perror("can't connect");
		exit(4);
	}
	gettimeofday(&tp, NULL);
	dt2 = tp.tv_sec+(tp.tv_usec/1000000.0); // stop timer
	printf("Connection established\n");
	printf("Open time: %.6lf seconds\n", dt2-dt1);
	
	/* before doing anything, send the password */
	printf("Attempting to send the password... %s\n", pw);
	if (write(sock, pw, strlen(pw)) == -1)
	{
		perror("write the password failed");
		exitSocket(sock, 5);
	}
	printf("Password sent!\n");
	
	/* Check that the password was accepted */
	if ((bytes = read(sock, servOut, MAX_READ)) > 0)
	{
		servOut[bytes] = '\0';
		printf("Server out is: '%s'\nAnd the size is: '%d'\n", servOut, bytes);
		if (strcmp(servOut, ACCEPTED) != 0)
		{
			fprintf(stderr, "The server returned '%s' and the okay is '%s'\n", servOut, ACCEPTED);
			perror("Invalid logon");
			exitSocket(sock, 6);
		}
		else
		{
			// send over the command!
			printf("You are now logged in!\n");
			printf("Sending command...\n");
			gettimeofday(&tp, NULL);
			dt3 = tp.tv_sec+(tp.tv_usec/1000000.0); // start the timer
			if (write(sock, cmd, strlen(cmd) + 1) == -1)
			{
				perror("sending command");
				exitSocket(sock, 7);
			}
			printf("Waiting for a response from the server\n");
			while ((bytes = read(sock, servOut, MAX_READ)) > 0)
			{
				printf("%s", servOut);
			}
		}
	}
	close(sock);
	gettimeofday(&tp, NULL);
	dt4 = tp.tv_sec+(tp.tv_usec/1000000.0); // stop the timer
	printf("Execute time: %.6lf seconds\n", dt4-dt3);
	
	return 0;
}

/*
 * This does the given exit as well as closing the given socket.
 * This should be used after a socket has been opened (just to make sure the
 * socket gets closed).
 */
void exitSocket(int sock, int exitNum)
{
	close(sock);
	exit(exitNum);
}

